//////////////////////////////////////////////////////////////////////
//
// NO_Referencer.h: interface for the NO_Referencer class.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
#ifndef NO_Referencer_H
#define NO_Referencer_H

//////////////////////////////////////////////////////////////////////////
#include "NO_Includes.h"

//////////////////////////////////////////////////////////////////////////
class NO_Value;
class NO_Type;

//////////////////////////////////////////////////////////////////////
// NO_Referencer Interface
//////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_NoneReferencer
{
protected:
	//////////////////////////////////////////////////////////////////////////
	NO_Value* getElementImpl		(NO_Value&, NO_UInt32)			const;
	NO_Value* getReferenceImpl		(NO_Value&)						const;
	NO_Value* getDereferenceImpl	(NO_Value&)						const; 
	NO_Value* getReflectImpl		(NO_Value&, void*, NO_UInt32)	const;
	NO_Value* getReplaceImpl		(NO_UInt32)						const;
};


//////////////////////////////////////////////////////////////////////
// NO_Referencer Interface
//////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_ReferencerFriendHelper
{
protected:
	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReflect(NO_Type const& rt, NO_Value&, void*, NO_UInt32) const;
};

//////////////////////////////////////////////////////////////////////////
// NO_ObjectReferencer
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ObjectReferencer
{
protected:
	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReflectImpl(NO_Value& d, void* o, NO_UInt32 n) const
	{
		T* p = reinterpret_cast<T*>(o);
		T* r = reinterpret_cast<T*>(noStartOfObject(p));
		if(p!=0){return new NO_ReferenceValue<T>(&r[n],&d);}
		throw std::exception("Invalid Type");
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReplaceImpl(NO_UInt32 num) const
	{
		return new NO_ReplaceValue<T>(num);
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReferenceImpl (NO_Value& obj) const
	{
		T* o = noGetDataException<T>(obj);
		return new NO_ReferenceValue<T*>(&o,&obj);
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getElementImpl (NO_Value& obj, NO_UInt32 n)	const 
	{
		if(n>=obj.getNum()){throw std::exception("index out of range");}
		T* o = noGetDataException<T>(obj);
		return new NO_ReferenceValue<T>(&o[n],&obj);
	}

	//////////////////////////////////////////////////////////////////////////
	virtual NO_Value* getDereferenceImpl(NO_Value& obj) const 
	{
		throw std::exception("Invalid Type for dereference operation");
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_Referencer
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_PointerReferencer : public NO_ReferencerFriendHelper
{
protected:
	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReflectImpl(NO_Value& d, void* o, NO_UInt32 n) const
	{
		T** p = reinterpret_cast<T**>(o);
		T** r = reinterpret_cast<T**>(noStartOfObject(p));
		if(p!=0){return new NO_ReferenceValue<T*>(&r[n],&d);}
		throw std::exception("Invalid Type");
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReplaceImpl(NO_UInt32 num) const
	{
		return new NO_ReplaceValue<T**>(num);
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getReferenceImpl (NO_Value& obj) const
	{
		T** o = noGetDataException<T*>(obj);
		return new NO_ReferenceValue<T**>(&o,&obj);
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getDereferenceImpl	(NO_Value& obj) const
	{
		T** o = noGetDataException<T*>(obj);
		if(!*o){return new NO_ReferenceValue<T>(*o,&obj);}
		const NO_Type& rt = NO_TypeID<>::type(typeid(**o));
		return getReflect(rt,obj,*o,0);	
	}

	//////////////////////////////////////////////////////////////////////////
	NO_Value* getElementImpl (NO_Value& obj, NO_UInt32 n)	const 
	{
		if(n>=obj.getNum()){throw std::exception("index out of range");}
		T** o = noGetDataException<T*>(obj);
		return new NO_ReferenceValue<T*>(&o[n],&obj);
	}
};

#endif
